package com.ybliang.plat.common.rpc.consumer.proxy;

import com.ybliang.plat.common.rpc.consumer.config.RpcClientProperties;
import com.ybliang.plat.common.rpc.consumer.netty.NettyClient;
import com.ybliang.plat.common.rpc.core.RpcRequest;
import com.ybliang.plat.common.rpc.core.RpcResponse;
import com.ybliang.plat.common.rpc.protocol.json.JSON;
import com.ybliang.plat.serviceapp.common.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.UUID;

/**
 * @author liangyb1
 */
public class RpcClientProxy<T> implements InvocationHandler {

    public static Logger LOGGER = LoggerFactory.getLogger(RpcClientProxy.class);

    private Class<T> interfaceClass;

    private RpcClientProperties rpcClientProperties;

    public RpcClientProxy(Class<T> interfaceClass, RpcClientProperties rpcClientProperties) {
        this.interfaceClass = interfaceClass;
        this.rpcClientProperties = rpcClientProperties;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        LOGGER.info("RpcFramework->referNetty() args: interfaceClass:{}, host:{}", interfaceClass.toString());
        String pkgName = interfaceClass.getPackage().getName();
        Optional<RpcClientProperties.RpcClient> optional =
                rpcClientProperties.getClients().values().stream().filter(n -> n.getBasePackages().equals(pkgName)).findFirst();
        if(!optional.isPresent()){
            //未配置rpc client异常
            throw new BusinessException();
        }
        RpcClientProperties.RpcClient rpcClient = optional.get();

        if(Object.class.equals(method.getDeclaringClass())) {
            try {
                // 诸如hashCode()、toString()、equals()等方法，将target指向当前对象this
                return method.invoke(this, args);
            } catch (Throwable e) {

            }
        }

//        if("toString".equals(method.getName())) {
//            LOGGER.info("RpcFramework->referNetty() method is toString() called...");
//            return interfaceClass.toString();
//        }

        RpcRequest request = new RpcRequest();
        request.setClassName(method.getDeclaringClass().getName());
        request.setMethodName(method.getName());
        request.setParameters(args);
        request.setParameterTypes(method.getParameterTypes());
        request.setId(UUID.randomUUID().toString());
        LOGGER.info("rpc request:{}", JSON.toJSONString(request));
        NettyClient nettyClient = new NettyClient(rpcClient.getIp(), rpcClient.getPort());
        try {
            nettyClient.connect();
        } catch (Exception e) {

        }

        String returnTypeName = method.getReturnType().getName();
        boolean isJavaUtilList = "java.util.List".equals(returnTypeName);

        RpcResponse response = nettyClient.send(request);
        LOGGER.info("rpc request:{}, response:{}",
                JSON.toJSONString(request),
                JSON.toJSONString(response));
        if(0 != response.getErrorCode()){
            //errorcode不为0，抛出异常
            throw new BusinessException(response.getErrorCode(), response.getErrorMsg());
        }

        if(null == response){
            LOGGER.info("rpc request:{} rpc response is null", JSON.toJSONString(request));
            return null;
        }
        if(!isJavaUtilList) {
            String resultJson = JSON.toJSONString(response.getResult());
            return JSON.parseObject(resultJson, method.getReturnType());
        }
        return response.getResult();
    }
}
